package com.ywx.intelligentaicodegeneration.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.ywx.intelligentaicodegeneration.constant.AppConstant;
import com.ywx.intelligentaicodegeneration.constant.UserConstant;
import com.ywx.intelligentaicodegeneration.core.AiCodeGeneratorFacade;
import com.ywx.intelligentaicodegeneration.exception.BusinessException;
import com.ywx.intelligentaicodegeneration.exception.ErrorCode;
import com.ywx.intelligentaicodegeneration.exception.ThrowUtils;
import com.ywx.intelligentaicodegeneration.mode.dto.app.AppQueryRequest;
import com.ywx.intelligentaicodegeneration.mode.dto.user.UserVO;
import com.ywx.intelligentaicodegeneration.mode.entity.App;
import com.ywx.intelligentaicodegeneration.mapper.AppMapper;
import com.ywx.intelligentaicodegeneration.mode.entity.User;
import com.ywx.intelligentaicodegeneration.mode.enums.ChatHistoryMessageTypeEnum;
import com.ywx.intelligentaicodegeneration.mode.enums.CodeGenTypeEnum;
import com.ywx.intelligentaicodegeneration.mode.vo.AppVO;
import com.ywx.intelligentaicodegeneration.service.AppService;
import com.ywx.intelligentaicodegeneration.service.ChatHistoryService;
import com.ywx.intelligentaicodegeneration.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.io.File;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 应用 服务层实现。
 *
 * @author <a href=\"https://gitee.com/JING5201314/aicode-gen-pro\">ywx</a>
 */
@Service
@Slf4j
public class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {

    @Resource
    private UserService userService;

    @Resource
    private AiCodeGeneratorFacade aiCodeGeneratorFacade;

    @Resource
    private ChatHistoryService chatHistoryService;


    @Override
    public Flux<String> chatToGenCode(String userMessage, Long appId, User loginUser) {
        //参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用id错误");
        ThrowUtils.throwIf(StrUtil.isBlank(userMessage), ErrorCode.PARAMS_ERROR, "用户输入提示词不能为空");
        //查询应用
        App app = getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        //权限校验,仅应用创建者可以访问
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限获取该应用");
        }
        //获取应用代码生成类型
        CodeGenTypeEnum codeGenTypeEnum = CodeGenTypeEnum.getEnumByValue(app.getCodeGenType());
        ThrowUtils.throwIf(codeGenTypeEnum == null, ErrorCode.PARAMS_ERROR, "代码生成类型错误");
        //添加用户输入的提示词到对话历史中
        chatHistoryService.addChatHistory(userMessage, ChatHistoryMessageTypeEnum.USER.getValue(), appId, loginUser.getId());
        //调用Ai生成代码(流式)
        Flux<String> contentFlux = aiCodeGeneratorFacade.generateAndSaveCodeStream(userMessage, codeGenTypeEnum, appId);
        //收集AI生成的内容并保存到对话历史中
        StringBuilder contentBuilder = new StringBuilder();
        return contentFlux.map(content -> {
            contentBuilder.append(content);
            return content;
        }).doOnComplete(() -> {
            String aiResponse = contentBuilder.toString();
            if (StrUtil.isNotBlank(aiResponse)) {
                chatHistoryService.addChatHistory(aiResponse, ChatHistoryMessageTypeEnum.AI.getValue(), appId, loginUser.getId());
            } else {
                chatHistoryService.addChatHistory(ErrorCode.SYSTEM_ERROR.getMessage(), ChatHistoryMessageTypeEnum.AI.getValue(), appId, loginUser.getId());
            }
        }).doOnError(error -> {
            //如果AI回复失败,也要记录错误信息
            String errorMessage = "AI回复失败:" + error.getMessage();
            chatHistoryService.addChatHistory(errorMessage, ChatHistoryMessageTypeEnum.AI.getValue(), appId, loginUser.getId());
        });
    }

    @Override
    public String deployApp(Long appId, User loginUser) {
        //1.校验参数
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用id错误");
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR, "未登录");
        //2.查询应用信息
        App app = getById(appId);
        //3.验证用户权限(只有应用创建者才能部署)
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无访问权限");
        }
        //4.检查是否已有deployKey(第一次部署),没有则生成
        String deployKey = app.getDeployKey();
        if (deployKey == null) {
            deployKey = RandomUtil.randomString(6);
        }

        //5.获取代码生成类型,构建源目录路径
        String codeGenType = app.getCodeGenType();
        String sourceDirName = codeGenType + "_" + appId;
        String sourceDirPath = AppConstant.CODE_OUTPUT_ROOT_DIR + File.separator + sourceDirName;

        //6.检查源目录是否存在
        File sourceDir = new File(sourceDirPath);
        if (!sourceDir.exists() || !sourceDir.isDirectory()) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "源目录不存在,请先生成代码");
        }
        //7.复制文件到部署目录
        String deployDirPath = AppConstant.CODE_DEPLOY_ROOT_DIR + File.separator + deployKey;
        try {
            FileUtil.copyContent(sourceDir, new File(deployDirPath), true);//覆盖之前部署的代码
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "部署失败:" + e.getMessage());
        }
        //8.更新应用的deployKey和部署时间
        App updateApp = new App();
        updateApp.setUpdateTime(LocalDateTime.now());
        updateApp.setId(appId);
        updateApp.setDeployKey(deployKey);
        boolean updateResult = updateById(updateApp);
        ThrowUtils.throwIf(!updateResult, ErrorCode.OPERATION_ERROR, "应用信息更新失败");
        //9.返回可访问的URL
        return String.format("%s/%s/", AppConstant.CODE_DEPLOY_HOST, deployKey);
    }


    @Override
    public AppVO getAppVO(App app) {
        if (app == null) {
            return null;
        }
        AppVO appVO = new AppVO();
        BeanUtil.copyProperties(app, appVO);
        // 关联查询用户信息
        Long userId = app.getUserId();
        if (userId != null) {
            User user = userService.getById(userId);
            UserVO userVO = userService.getUserVO(user);
            appVO.setUser(userVO);
        }
        return appVO;
    }

    @Override
    public QueryWrapper getQueryWrapper(AppQueryRequest appQueryRequest) {
        if (appQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        Long id = appQueryRequest.getId();
        String appName = appQueryRequest.getAppName();
        String cover = appQueryRequest.getCover();
        String initPrompt = appQueryRequest.getInitPrompt();
        String codeGenType = appQueryRequest.getCodeGenType();
        String deployKey = appQueryRequest.getDeployKey();
        Integer priority = appQueryRequest.getPriority();
        Long userId = appQueryRequest.getUserId();
        String sortField = appQueryRequest.getSortField();
        String sortOrder = appQueryRequest.getSortOrder();
        return QueryWrapper.create()
                .eq("id", id)
                .like("appName", appName)
                .like("cover", cover)
                .like("initPrompt", initPrompt)
                .eq("codeGenType", codeGenType)
                .eq("deployKey", deployKey)
                .eq("priority", priority)
                .eq("userId", userId)
                .orderBy(sortField, "ascend".equals(sortOrder));
    }

    @Override
    public List<AppVO> getAppVOList(List<App> appList) {
        if (CollUtil.isEmpty(appList)) {
            return new ArrayList<>();
        }
        // 批量获取用户信息，避免 N+1 查询问题
        Set<Long> userIds = appList.stream()
                .map(App::getUserId)
                .collect(Collectors.toSet());
        Map<Long, UserVO> userVOMap = userService.listByIds(userIds).stream()
                .collect(Collectors.toMap(User::getId, userService::getUserVO));
        return appList.stream().map(app -> {
            AppVO appVO = getAppVO(app);
            UserVO userVO = userVOMap.get(app.getUserId());
            appVO.setUser(userVO);
            return appVO;
        }).collect(Collectors.toList());
    }

    /**
     * 删除应用(关联删除对话历史)
     *
     * @param id
     * @return
     */
    @Override
    public boolean removeById(Serializable id) {
        if (id == null) {
            return false;
        }
        Long appId = (Long) id;
        if (appId <= 0) {
            return false;
        }
        try {
            //先删除对话历史
            chatHistoryService.deleteByAppId(appId);
        } catch (Exception e) {
            //记录日志单是不阻应用删除
            log.error("删除对话历史失败:" + e.getMessage());
        }
        //删除应用
        return super.removeById(id);
    }

    @Override
    public boolean PermissionCheck(Long appId, User loginUser, boolean adminIsTrue) {
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用Id错误");
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        App app = this.getById(appId);
        if (app == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        }
        //如果是应用创建者，则返回true
        if (app.getUserId().equals(loginUser.getId())) {
            return true;
        }
        //如果管理员也有权限且是管理员，则返回true
        if (adminIsTrue && UserConstant.ADMIN_ROLE.equals(loginUser.getUserRole())) {
            return true;
        }
        return false;

    }
}
